﻿using System;
using jade.core;
using jade.core.behaviours;
using jade.lang.acl;
using System.Threading;
using jade.domain.FIPAAgentManagement;
using jade.content.lang;
using log4net;
using GatewayUtil.RequestResponse;
using jade.content;
using jade.content.lang.leap;
using Action = jade.content.onto.basic.Action;
using jade.domain.JADEAgentManagement;
using jade.content.onto.basic;



namespace GatewayUtil.agents
{
    /// <summary>
    /// Communication point between MAS and other world. All requests that were put into GWAgent queue will be forwarded to concrete agent.
    /// </summary>
    public class GatewayAgent : Agent
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(GatewayAgent));

        public static Codec codec = new LEAPCodec();
        //public static Codec codec = new SLCodec();
        public override void setup()
        {
            log.Info("Starting agent with name "+this.getAID().getLocalName());


            getContentManager().registerLanguage(codec);
            getContentManager().registerOntology(FIPAManagementOntology.getInstance());
            getContentManager().registerOntology(JADEManagementOntology.getInstance());

            this.getContentManager().setValidationMode(false);

            this.setEnabledO2ACommunication(true, 30);

            addBehaviour(new GatewayBehaviour(this));
            debug("Gateway agent is set up!");
        }

        public override void takeDown()
        {
            base.takeDown();
            log.Info("Agent "+this.getAID().getLocalName()+" taken down!");
        }

        private void debug(string p)
        {
            log.Debug(this.getLocalName() + ": " + p);

        }
        private void error(string p)
        {
            log.Error(this.getLocalName() + ": " + p);
        }

        private void error(Exception e)
        {
            log.Error(e);
        }


        class GatewayBehaviour : SimpleBehaviour
        {
            
            bool finished = false;
            public GatewayBehaviour(Agent a):base(a)
            {
                ((GatewayAgent)this.myAgent).debug("Gateway behaviour started!");
            }

            public override void action()
            {
                try
                {
                    ((GatewayAgent)this.myAgent).debug("GatewayAgent's behaviour is ready");
                    DataObject data = (DataObject)base.myAgent.getO2AObject();
                    if (data != null)
                    {
                        ((GatewayAgent)this.myAgent).debug("Received request: " + data.getRequest());
                        IRequest request = data.getRequest();

                        ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
                        msg.setLanguage(GatewayAgent.codec.getName());
                        
                        this.myAgent.getContentManager().registerOntology(data.getOntology());
                        msg.setOntology(data.getOntology().getName());                        
                        
                        msg.addReceiver(request.getReceiver());

                        Action action = new Action(request.getReceiver(), (AgentAction)request.getRequest());
                        this.myAgent.getContentManager().fillContent(msg, action);

                        base.myAgent.send(msg);

                        msg = base.myAgent.blockingReceive();

                        log.Debug("Received response");
                        
                        // extract a result object
                        ContentElement contentE = (ContentElement)myAgent.getContentManager().extractContent(msg);
                        Result res = (Result)contentE;
                        Object val = res.getValue();

                        if (val is Concept)
                        {
                            IResponse response = new Response();
                            response.setResponse((Concept)val);
                            data.setResponse(response);
                        }
                        else
                        {
                            log.Error("Object is not a AgentAction! is a " + ((Concept)val).GetType().FullName);
                        }
                        

                        ((GatewayAgent)this.myAgent).debug("Releasing request back to external world");
                        lock (data) Monitor.Pulse(data);
                        ((GatewayAgent)this.myAgent).debug("Request released....");
                    } block();
                }
                catch(Exception e)
                {
                    log.Error("Exception in GatewayAgent",e);
                    throw e;
                }
            }


            public override bool done()
            {
                return finished;
            }
        }




        }
    }



